﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Communication.Net.Base;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.Communication.Net.Ftp
{
    /// <summary>
    /// Ftp服务器类
    /// </summary>
    public class FtpServer : IDisposable
    {
        private readonly FtpConfig _config;
        /// <summary>
        /// ftp配置
        /// </summary>
        public FtpConfig Config
        {
            get { return _config; }
        }

        private readonly NetTcpListener _tcpListener;
        private readonly List<FtpSession> _sessions = new List<FtpSession>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="config">ftp配置</param>
        /// <exception cref="ArgumentNullException">ftp配置为null将抛出异常</exception>
        public FtpServer(FtpConfig config)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            config.MergePath();//合并用户所有权限的多个路径
            this._config = config;
            var initPara = new NetTcpListenerInitPara(config.EndPoint, config.Backlog);
            //initPara.AcceptMode = ThreadMode.Sync;
            //initPara.SyncThreadName =$"Ftp{NetHelper.GetIPPortString(config.EndPoint)}监听线程";
            this._tcpListener = new NetTcpListener(this.AcceptSocketCallback, initPara);
        }

        private void AcceptSocketCallback(AcceptSocketArgs args)
        {
            try
            {
                try
                {
                    try
                    {
                        var session = new FtpSession(this, args.Client, this.FtpSessionCloseCallback);
                        lock (this._sessions)
                        {
                            this._sessions.Add(session);
                        }
                        session.StartReceiveCommand();
                    }
                    catch (Exception exi)
                    {
                        ZLoger.Warn(exi);
                        args.Client.Dispose();
                    }
                }
                catch (SocketException sex)
                {
                    if (!NetHelper.SocketErrorIsDisconnect(sex.SocketErrorCode))
                    {
                        ZLoger.Error(sex);
                    }
                }
                catch (Exception exi)
                {
                    ZLoger.Error(exi);
                }
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }

        private void FtpSessionCloseCallback(FtpSession session)
        {
            lock (this._sessions)
            {
                this._sessions.Remove(session);
                session.Dispose();
            }
        }

        /// <summary>
        /// 启动FTP服务器
        /// </summary>
        public void Start()
        {
            this._tcpListener.Start();
            ZLoger.Debug($"FtpSever is running at ftp://{NetHelper.GetIPPortString(this._config.EndPoint)}");
        }

        /// <summary>
        /// 停止FTP服务器
        /// </summary>
        public void Stop()
        {
            this._tcpListener.Stop();
        }

        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            this.Stop();

            this._tcpListener.Dispose();
            lock (this._sessions)
            {
                foreach (var session in this._sessions)
                {
                    session.Dispose();
                }
                this._sessions.Clear();
            }
        }
    }
}
